package com.hivekion.common.filter;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.hivekion.common.entity.vo.LoginUser;
import com.hivekion.common.exception.BusinessException;
import com.hivekion.common.redis.RedisUtil;
import com.hivekion.common.security.JwtTokenUtils;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

/**
 * 登录认证检查过滤器
 *
 * @author sutao
 * @date 2021-3-23
 */
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

      @Autowired
      RedisUtil redisUtil;

      @Autowired
      public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
	    super(authenticationManager);
      }

      public JwtAuthenticationFilter(
	      AuthenticationManager authenticationManager,
	      AuthenticationEntryPoint authenticationEntryPoint) {
	    super(authenticationManager, authenticationEntryPoint);
      }

      @Override
      protected void doFilterInternal(
	      HttpServletRequest request, HttpServletResponse response, FilterChain chain)
	      throws IOException, ServletException {
	    // 获取容器
	    ServletContext context = request.getServletContext();
	    ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);
	    redisUtil = ctx.getBean(RedisUtil.class);
	    try {
		  Authentication authentication = getAuthentication(request);
		  SecurityContextHolder.getContext().setAuthentication(authentication); // 设置登录认证信息到上下文
		  chain.doFilter(request, response);
	    } catch (ExpiredJwtException ex) {
		  logger.error("Token已过期: {} " + ex);
	    }
      }

      public Authentication getAuthentication(HttpServletRequest request) {
	    Authentication authentication = null;
	    String token = JwtTokenUtils.getToken(request); // 获取请求携带的令牌
	    if (token == null) {
		  throw new BusinessException(500, "未找到授权信息");
	    }
	    try {
		  String userName = JwtTokenUtils.getUsernameFromToken(token);
		  if (StringUtils.isNotBlank(userName)) {
			Object usernameByToken =
				JSON.parseObject(
					redisUtil.getUsernameByToken(token).toString(), LoginUser.class);
			if (usernameByToken instanceof LoginUser) {
			      LoginUser user = (LoginUser) usernameByToken;
			      authentication =
				      new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
			}
		  }
		  return authentication;
	    } catch (ExpiredJwtException ex) {
		  throw ex; // Token已过期
	    } catch (UnsupportedJwtException ex) {
		  throw ex; // Token格式错误
	    } catch (MalformedJwtException ex) {
		  throw ex; // Token没有被正确构造
	    } catch (IllegalArgumentException ex) {
		  throw ex; // 非法参数异常
	    } catch (Exception e) {
		  throw e;
		  // throw new IllegalStateException("Invalid Token. "+e.getMessage());
	    }
      }
}
